昨天有提到我們在使用Config的時候,可以透過將設定綁定到POCO物件上的方式做使用
然後註冊該物件,並直接注入該物件做使用
但是如果是直接入物件的話,使用該Config的Service某種程度就會直接依賴該POCO
所以這時候應該透過介面來隔離他們,因此有了選項模式IOption<T>
我們繼續用之前的appsettings.json 作為範例
{
"line": {
"channelId": "line_channel_id",
"channelSecret": "line_channel_secret",
"info": {
"name": "line_bot_name",
"pictureUrl": "line_bot_picture_url"
}
},
"facebook": {
"pageId": "facebook_page_id",
"accessToken": "facebook_page_access_token",
"appSecret": "facebook_app_secret"
},
"telegram": {
"botToken": "telegram_bot_token"
}
}
Program.cs
var settingFile = @"appsettings.json";
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile(settingFile)
.Build();
var serviceProvider = new ServiceCollection()
.AddOptions()
.Configure<LineSetting>(configuration.GetSection("Line"))
.BuildServiceProvider();
var option = serviceProvider.GetService<IOptions<LineSetting>>();
Console.WriteLine(option.Value.ChannelId);
可以看見在上方我用了AddOption()
的擴充方法去註冊選項模式所需的物件,因為是Console,WebSdk的Host中本身已有這段所以不用特別加
然後再透過 Configure<T>
方法去將對應的IConfiguration
綁定到選項上
在Service中則可以這樣注入使用
public class LineService
{
private readonly IOptions<LineSetting> _lineSetting;
public LineService(IOptions<LineSetting> lineSetting)
{
_lineSetting = lineSetting;
}
public void PrintLineAppName()
{
Console.WriteLine(_lineSetting.Value.Info.Name);
}
}
在每次請求或注入IOptionSnapshot\<T>
的時候,
會去讀取一次當前Scope的IConfiguration
已就是說,他是可以監控設定的變化的IOption<T>
註冊的方式一樣用 Configure就行
var serviceProvider = new ServiceCollection()
.AddOptions()
.Configure<LineSetting>(configuration.GetSection("Line"))
.BuildServiceProvider();
但注入的時候型別使用IOptionSnapshot\<T>
public class LineService
{
private readonly IOptionsSnapshot<LineSetting> _lineSetting;
public LineService(IOptionsSnapshot<LineSetting> lineSetting)
{
_lineSetting = lineSetting;
}
public void PrintLineAppName()
{
Console.WriteLine(_lineSetting.Value.Info.Name);
}
}
跟IOptionSnapshot
一樣,可以根據檔案的變化重新bind Entity
使用方式也很像Program.cs
var serviceProvider = new ServiceCollection()
.AddOptions()
.Configure<LineSetting>(configuration.GetSection("Line"))
.BuildServiceProvider();
注入的時候型別使用IOptionsMonitor\<T>
且讀取Option的時候使用的是 CurrentValue
public class LineService
{
private readonly IOptionsMonitor<LineSetting> _lineSetting;
public LineService(IOptionsMonitor<LineSetting> lineSetting)
{
_lineSetting = lineSetting;
}
public void PrintLineAppName()
{
Console.WriteLine(_lineSetting.CurrentValue.Info.Name);
}
}
IOptionSnapshot<T>
跟 IOptionMonitor\<T>
主要差異在IOptionMonitor
的Lifetime被註冊為Singleton
而 IOptionSnapshot
則是Scoped
的
另外IOptionMonitor\<T>
還提供了一個方法OnChange(Action<TOptions, string> listener)
可以在設定檔變更時候自訂要觸發的事件。